package com.svconnect.plugin.views;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import com.svconnect.plugin.Activator;
import com.svconnect.plugin.preferences.PreferenceConstants;


/**
 * This sample class demonstrates how to plug-in a new workbench view. The view
 * shows data obtained from the model. The sample creates a dummy model on the
 * fly, but a real implementation would connect to the model available either in
 * this or another plug-in (e.g. the workspace). The view is connected to the
 * model using a content provider.
 * <p>
 * The view uses a label provider to define how model objects should be
 * presented in the view. Each view can present the same model objects using
 * different labels and icons, if needed. Alternatively, a single label provider
 * can be shared between views in order to ensure that objects of the same type
 * are presented in the same way everywhere.
 * <p>
 */

public class ServiceReferenceView extends ViewPart implements IResourceChangeListener {

	/**
	 * The ID of the view as specified by the extension.
	 */
	public static final String ID = "com.svconnect.plugin.views.ServiceReferenceView";

	private TableViewer viewer;
	private Action addReferenceAction;
	private Action deleteReferenceAction;
	private Action referenceDetailsAction;

	private IProject activeProject;

	/*
	 * The content provider class is responsible for providing objects to the
	 * view. It can wrap existing objects in adapters or simply return objects
	 * as-is. These objects may be sensitive to the current input of the view,
	 * or ignore it and always show the same content (like Task List, for
	 * example).
	 */

	class ViewContentProvider implements IStructuredContentProvider {

		public void inputChanged(Viewer v, Object oldInput, Object newInput) {
		}

		public void dispose() {
		}

		public Object[] getElements(Object parent) {
			if (activeProject != null) {
				String buildPath = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_BUILD_PATH);
				String path = String.format("%s/%s", activeProject.getLocation().toString(), buildPath);
				File dir = new File(path);
				if (dir.exists() && dir.isDirectory()) {
					File[] files = dir.listFiles(new FileFilter() {
						@Override
						public boolean accept(File f) {
							return f.isDirectory();
						}
					});
					String[] refs = new String[files.length];
					for(int i=0; i<files.length; i++) {
						refs[i] = files[i].getName();
					}
					return refs;
				}
			}
			return new String[0];
		}
	}

	class ViewLabelProvider extends LabelProvider implements
			ITableLabelProvider {
		public String getColumnText(Object obj, int index) {
			return getText(obj);
		}

		public Image getColumnImage(Object obj, int index) {
			return getImage(obj);
		}

		public Image getImage(Object obj) {
			return PlatformUI.getWorkbench().getSharedImages()
					.getImage(ISharedImages.IMG_OBJ_ELEMENT);
		}
	}

	class NameSorter extends ViewerSorter {
		public int compare(Viewer viewer, Object e1, Object e2) {
			return ((String)e1).compareTo((String)e2);
		}
	}

	/**
	 * The constructor.
	 */
	public ServiceReferenceView() {
	}

	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.setSorter(new NameSorter());
		viewer.setInput(getViewSite());
		// Create the help context id for the viewer's control
		PlatformUI.getWorkbench().getHelpSystem()
				.setHelp(viewer.getControl(), "WCFSupportPlugin.viewer");
		makeActions();
		hookContextMenu();
		hookDoubleClickAction();
		contributeToActionBars();

		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				ISelection selection = event.getSelection();
				Object obj = ((IStructuredSelection) selection)
						.getFirstElement();
				deleteReferenceAction.setEnabled(obj != null);
			}
		});
		
		addReferenceAction.setEnabled(false);
		deleteReferenceAction.setEnabled(false);
		ResourcesPlugin.getWorkspace().addResourceChangeListener(this);

		hookActiveProjectChanged();
	}
	
	@Override
	public void resourceChanged(IResourceChangeEvent event) {
		Display.getDefault().asyncExec(new Runnable() {
			@Override
			public void run() {
				if (activeProject!=null) {
					String projectPath = activeProject.getLocation().toString();
					String buildPath = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_BUILD_PATH);
					File dir = new File(String.format("%s/%s", projectPath, buildPath));
					if (dir.exists() && dir.isDirectory()) {
						File[] files = dir.listFiles();
						for(File f : files ){
							if (f.isDirectory() && f.listFiles().length==0) {
								f.delete();
							}
						}
					}
					viewer.refresh();
				}
			}
		});
	}	
	
	@Override
	public void dispose() {
        super.dispose();
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
	}
	

	private void hookActiveProjectChanged() {
		ISelectionService selectionService = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow().getSelectionService();

		ISelectionListener listener = new ISelectionListener() {

			public void selectionChanged(IWorkbenchPart sourcePart,
					ISelection selection) {
				IProject project = null;

				if (selection != null) {
					IWorkbenchPage page = getSite().getWorkbenchWindow()
							.getActivePage();
					IEditorPart editorPart = page!=null ? page.getActiveEditor() : null;
					if (editorPart != null) {
						IFileEditorInput input = (IFileEditorInput) editorPart
								.getEditorInput();
						IFile file = input.getFile();
						project = file.getProject();
					}

					if (selection instanceof IStructuredSelection) {
						Object element = ((IStructuredSelection) selection)
								.getFirstElement();
						if (element instanceof IResource) {
							project = ((IResource) element).getProject();
						} else if (element instanceof IJavaElement) {
							IJavaProject jProject = ((IJavaElement) element)
									.getJavaProject();
							project = jProject.getProject();
						}
					}

					if (project != null) {
						activeProjectChanged(project);
					}
				}

			}
		};
		selectionService.addSelectionListener(listener);
		listener.selectionChanged(null, selectionService.getSelection());
	}

	private void activeProjectChanged(IProject project) {
		if (activeProject == null || project == null || !project.equals(activeProject)) {
			this.activeProject = project;
			if (this.viewer != null)
				viewer.refresh();
			this.addReferenceAction.setEnabled(this.activeProject!=null);
			/*
			String partName = "Service References";
			if (this.activeProject!=null)
				partName += String.format(" (%s)",activeProject.getName());
			
			this.setPartName(partName);
			*/
		}
	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				ServiceReferenceView.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menuMgr, viewer);
	}

	private void contributeToActionBars() {
		IActionBars bars = getViewSite().getActionBars();
		fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}

	private void fillLocalPullDown(IMenuManager manager) {
		manager.add(addReferenceAction);
		manager.add(new Separator());
		manager.add(deleteReferenceAction);
	}

	private void fillContextMenu(IMenuManager manager) {
		manager.add(addReferenceAction);
		manager.add(deleteReferenceAction);
		// Other plug-ins can contribute there actions here
		manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
	}

	private void fillLocalToolBar(IToolBarManager manager) {
		manager.add(addReferenceAction);
		manager.add(deleteReferenceAction);
	}

	private void makeActions() {
		addReferenceAction = new Action() {
			public void run() {
				addReference();
			}
		};
		addReferenceAction.setText("Add Service Reference");
		addReferenceAction.setToolTipText("Add Service Reference");
		addReferenceAction.setImageDescriptor(PlatformUI.getWorkbench()
				.getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD));

		addReferenceAction.setDisabledImageDescriptor(PlatformUI.getWorkbench()
				.getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD_DISABLED));

		
		deleteReferenceAction = new Action() {
			public void run() {
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection)
						.getFirstElement();
				deleteReference((String)obj);
			}
		};
		deleteReferenceAction.setText("Delete");
		deleteReferenceAction.setToolTipText("Delete");
		deleteReferenceAction.setImageDescriptor(PlatformUI.getWorkbench()
				.getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_ETOOL_DELETE));
		deleteReferenceAction.setDisabledImageDescriptor(PlatformUI
				.getWorkbench().getSharedImages()
				.getImageDescriptor(ISharedImages.IMG_ETOOL_DELETE_DISABLED));

		referenceDetailsAction = new Action() {
			public void run() {
				ISelection selection = viewer.getSelection();
				Object obj = ((IStructuredSelection) selection).getFirstElement();
				showDetails(obj.toString());
			}
		};
	}

	private void addReference() {
		if (activeProject!=null) {
			AddReferenceDialog dialog = new AddReferenceDialog(getSite().getShell(), this.activeProject);
	        dialog.open();
		}
	}

	private void deleteReference(String referenceName) {
		if (activeProject!=null) {
			boolean confirmed = MessageDialog.openConfirm(getSite().getShell(), "Delete Service Reference", "Are you sure want to delete "+referenceName+" service reference?");
			if (confirmed) {
				String buildPath = Activator.getDefault().getPreferenceStore().getString(PreferenceConstants.P_BUILD_PATH);
				String path = String.format("%s/%s/%s/src", activeProject.getFullPath().toString(), buildPath, referenceName);
				if (removeClasspathEntry(activeProject,path)) {
					String fullpath = String.format("/%s/%s/%s", activeProject.getLocation().toString(), buildPath, referenceName);
					File dir = new File(fullpath);
					if (dir.exists() && dir.isDirectory()) {
						this.clearDir(dir);
						dir.delete();
						try {
							activeProject.refreshLocal(IResource.DEPTH_INFINITE, null);
						} catch (CoreException e) {}
					}
				}
			}
		}
			
	}
	
	private boolean removeClasspathEntry(IProject project, String cp) {
		try {
			IJavaProject javaProject = JavaCore.create(project);
			IClasspathEntry[] entries = javaProject.getRawClasspath();
			List<IClasspathEntry> entriesList = new ArrayList<IClasspathEntry>();
			for(int i=0; i<entries.length; i++) {
				String entryCp = entries[i].getPath().toString();
				if (!entryCp.equals(cp)) {
					entriesList.add(entries[i]);
				}
			}

			IClasspathEntry[] newEntries = new IClasspathEntry[entriesList.size()];
			newEntries = entriesList.toArray(newEntries);
			javaProject.setRawClasspath(newEntries, null);
			return true;
			
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		
	}		
	
	private void showDetails(String referenceName) {
		// TODO:
	}
	
	protected boolean clearDir(File dir) {
		File[] files = dir.listFiles();
		boolean success = true;
		for (File file : files)
		{
			if (file.isDirectory()) {
				success &= clearDir(file);
			}
			success &= file.delete();
		}
		return success;
	}	
	

	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				referenceDetailsAction.run();
			}
		});
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
}